package com.example.basic.web.service.pharmZone.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.basic.base.impl.BaseEntityServiceImpl;
import com.example.basic.exception.ServiceException;
import com.example.basic.utils.*;
import com.example.basic.utils.excel.EasyExcelUtils;
import com.example.basic.web.enums.DataCodeEnum;
import com.example.basic.web.enums.EnableTypeEnum;
import com.example.basic.web.mapper.pharmZone.PharmZoneMapper;
import com.example.basic.web.model.pharmZone.PharmZone;
import com.example.basic.web.model.zoneChannel.ZoneChannel;
import com.example.basic.web.model.zoneDepot.ZoneDepot;
import com.example.basic.web.service.dataCode.DataCodeService;
import com.example.basic.web.service.pharmZone.PharmZoneService;
import com.example.basic.web.service.zoneChannel.ZoneChannelService;
import com.example.basic.web.service.zoneDepot.ZoneDepotService;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static com.example.basic.utils.CheckUtil.notNull;


@Service
public class PharmZoneServiceImpl extends BaseEntityServiceImpl<PharmZoneMapper, PharmZone> implements PharmZoneService {

    @Resource
    private PharmZoneMapper pharmZoneMapper;

    @Resource
    private DataCodeService dataCodeService;

    @Resource
    private ZoneChannelService zoneChannelService;

    @Resource
    private ZoneDepotService zoneDepotService;


    /**
     * 保存或者修改
     * @param pharmZone 模型
     * @return
     */
    @Override
    public PharmZone addOrUpdate(PharmZone pharmZone) {
        //参数检验
        notNull(pharmZone.getZoneName(),"分区名称不能为空");
        notNull(pharmZone.getPharmCode(),"仓库编码不能为空");
        notNull(pharmZone.getLayerNum(),"层数不能为空");
        notNull(pharmZone.getRowsNum(),"行数不能为空");
        notNull(pharmZone.getColumnNum(),"列数不能为空");
        notNull(pharmZone.getHighLimit(),"高限位不能为空");
        notNull(pharmZone.getLowLimit(),"低限位不能为空");
        //校验名称是否重复
        LambdaQueryWrapper<PharmZone> lqw = new LambdaQueryWrapper<>();
        lqw.eq(PharmZone::getZoneName,pharmZone.getZoneName());
        lqw.eq(PharmZone::getPharmCode,pharmZone.getPharmCode());
        if (pharmZone.getId() != null){
            notNull(pharmZone.getZoneCode(),"分区编码不能为空");
            lqw.ne(PharmZone::getZoneCode,pharmZone.getZoneCode());
        }
        PharmZone detail = pharmZoneMapper.selectOne(lqw);
        if(detail != null){
            throw new ServiceException("当前分区名称已存在");
        }
        //修改
        if (pharmZone.getId() != null){
            preUpdate(pharmZone);
        }
        //新增
        else {
            //生成分区编码
            String zoneCode = dataCodeService.generateDataCodeNo(DataCodeEnum.ZONE_CODE.getType());
            pharmZone.setZoneCode(zoneCode);
            preCreate(pharmZone);
        }

        //生成拼音码五笔码
        generatePyWbCode(pharmZone);

        this.save(pharmZone);
        return detail(pharmZone.getZoneCode());
    }

    /**
     * @create 生成五笔码、拼音码
     * @param pharmZone 系统用户模型实体类
     */
    private void generatePyWbCode(PharmZone pharmZone) {
        // 获取分区名
        String zoneName = StringUtils.safeToString(pharmZone.getZoneName(), "");
        // 生成拼音码
        if("".equals(StringUtils.safeToString(pharmZone.getPyCode(),"").replaceAll(" ",""))) {
            String userNamePinyin = PinyinUtils.getSimplePinYin(zoneName);
            pharmZone.setPyCode(userNamePinyin);
        }
        // 生成拼音码
        if("".equals(StringUtils.safeToString(pharmZone.getWbCode(),"").replaceAll(" ",""))) {
            String userNameWubi = WubiUtils.getSimpleWuBi(zoneName);
            pharmZone.setWbCode(userNameWubi);
        }
    }

    /**
     * 详情
     * @param zoneCode 分区编码
     * @return
     */
    @Override
    public PharmZone detail(String zoneCode) {
        notNull(zoneCode, "分区编码不能为空");

        return  pharmZoneMapper.detail(zoneCode);
    }

    /**
     * 删除
     * @param zoneCode 分区编码
     * @return
     */
    @Override
    public int delete(String zoneCode) {
        notNull(zoneCode,"分区编码不能为空");

        PharmZone pharmZone = detail(zoneCode);
        if(pharmZone == null){
            throw new ServiceException("未查询到当前数据");
        }

        //校验是否存在在用通道
        List<ZoneChannel> list = zoneChannelService.queryByZone(zoneCode);
        if (list != null && list.size() > 0){
            throw new ServiceException("当前分区存在在用通道,不允许删除");
        }

        //校验是否存在在用库位
        IPage<ZoneDepot> zoneDepotIPage = zoneDepotService.queryList(new Page<>(0, 0), null, "0", zoneCode, pharmZone.getPharmCode());
        if(zoneDepotIPage.getRecords().size() > 0){
            throw new ServiceException("存在在用库位，不允许删除");
        }

        //删除库区通道
        zoneChannelService.removeByZone(zoneCode);
        //删除库位信息
        zoneDepotService.removeByZone(zoneCode);

        return this.mapper.deleteById(pharmZone.getId());
    }

    /**
     * 启用/禁用
     * @param zoneCode 分区编码
     * @return
     */
    @Override
    public int enableOrDisable(String zoneCode) {
        notNull(zoneCode,"分区编码不能为空");

        PharmZone pharmZone = detail(zoneCode);

        if(pharmZone == null){
            throw new ServiceException("未查询到当前数据");
        }

        //校验是否存在在用库位
        IPage<ZoneDepot> zoneDepotIPage = zoneDepotService.queryList(new Page<>(0, 0), null, "0", zoneCode, pharmZone.getPharmCode());
        if(zoneDepotIPage.getRecords().size() > 0){
            throw new ServiceException("存在在用库位，不允许操作");
        }

        //停用启用
        if(pharmZone.getEnableFlag().equals(EnableTypeEnum.ON.getType())){
            pharmZone.setEnableFlag(EnableTypeEnum.OFF.getType());
        }else {
            pharmZone.setEnableFlag(EnableTypeEnum.ON.getType());
        }

        preUpdate(pharmZone);

        return this.mapper.updateById(pharmZone);
    }

    /**
     * 分区列表
     *
     * @param queryPage   分页
     * @param searchParam 模糊搜索(拼音码,五笔码,名称,编码)
     * @param isAll       是否查询全部 0-否，1-是
     * @param pharmCode 仓库编码
     * @return
     */
    @Override
    public IPage<PharmZone> queryList(Page<PharmZone> queryPage, String searchParam, String isAll, String pharmCode) {
        return pharmZoneMapper.queryList(queryPage,searchParam,isAll,pharmCode);
    }

    /**
     * 查询仓库下在用分区
     * @param pharmCode 仓库编码
     * @return
     */
    @Override
    public List<PharmZone> queryByPharm(String pharmCode) {
        notNull(pharmCode,"仓库编码不能为空");

        LambdaQueryWrapper<PharmZone> lqw = new LambdaQueryWrapper<>();
        lqw.eq(PharmZone::getPharmCode,pharmCode);
        lqw.eq(PharmZone::getEnableFlag,EnableTypeEnum.ON.getType());

        return this.mapper.selectList(lqw);
    }

    /**
     * 分区数据导入
     * @param file 文件
     * @param pharmCode 仓库编码
     * @return
     */
    @Override
    public Boolean importData(MultipartFile file, String pharmCode) {
        notNull(pharmCode,"仓库编码不能为空");

        //需要保存的数据元列表
        List<PharmZone> pharmZoneList = new ArrayList<>();

        InputStream in = null;

        try {
            in = file.getInputStream();
        } catch (IOException e) {
            throw new ServiceException("文件读取异常");
        }
        // 工作表
        Workbook workbook = null;

        try {
            if(ExcelUtils.judegExcelEdition(file.getOriginalFilename())){
                workbook = new XSSFWorkbook(in);

            }else{
                workbook = new HSSFWorkbook(in);
            }
        } catch (IOException e) {
            throw new ServiceException("文件类型转换错误！");
        }

        if(workbook == null){
            throw new ServiceException("文件类型错误！");
        }

        // 遍历表。
        Sheet sheet = workbook.getSheetAt(0);

        // 行数。
        int rowNumbers = sheet.getLastRowNum() + 1;

        // Excel第一行。
        Row temp = sheet.getRow(0);
        if (temp == null) {
            throw new ServiceException("未获取到需要导入的数据!");
        }

        DataFormatter dataFormatter = new DataFormatter();
        // 读数据。
        for (int row = 0; row < rowNumbers; row++) {
            Row r = sheet.getRow(row);
            PharmZone pharmZone = new PharmZone();
            if (row > 0) {
                pharmZone.setPharmCode(pharmCode);
                if(r.getCell(0) == null){
                    throw new ServiceException("分区名称不能为空!");
                }
                pharmZone.setZoneName(dataFormatter.formatCellValue(r.getCell(0)));
                if(r.getCell(1) == null){
                    throw new ServiceException("层数不能为空!");
                }
                pharmZone.setLayerNum(Integer.getInteger(dataFormatter.formatCellValue(r.getCell(1))));
                if(r.getCell(2) == null){
                    throw new ServiceException("行数不能为空!");
                }
                pharmZone.setRowsNum(Integer.getInteger(dataFormatter.formatCellValue(r.getCell(2))));
                if(r.getCell(3) == null){
                    throw new ServiceException("列数不能为空!");
                }
                pharmZone.setColumnNum(Integer.getInteger(dataFormatter.formatCellValue(r.getCell(4))));
                if(r.getCell(4) == null){
                    throw new ServiceException("高限位不能为空!");
                }
                pharmZone.setHighLimit(Integer.getInteger(dataFormatter.formatCellValue(r.getCell(5))));
                if(r.getCell(5) == null){
                    throw new ServiceException("低限位不能为空!");
                }
                pharmZone.setLowLimit(Integer.getInteger(dataFormatter.formatCellValue(r.getCell(6))));

                //获取拼音码五笔码
                generatePyWbCode(pharmZone);
                pharmZone.setEnableFlag(EnableTypeEnum.ON.getType());
                pharmZoneList.add(pharmZone);
            }
        }

        if(pharmZoneList.size() == 0){
            throw new ServiceException("文件为空文件");
        }

        //数据唯一校验
        List<String> zoneNames = pharmZoneList.stream().distinct().map(PharmZone::getZoneName).collect(Collectors.toList());
        if(zoneNames.size() < pharmZoneList.size()){
            throw new ServiceException("文件存在重复分区名称");
        }

        //校验数据库数据唯一
        LambdaQueryWrapper<PharmZone> lqw = new LambdaQueryWrapper<>();
        lqw.in(PharmZone::getZoneName,zoneNames);
        lqw.eq(PharmZone::getPharmCode,pharmCode);
        List<PharmZone> localList = this.mapper.selectList(lqw);

        if(localList.size() > 0){
            throw new ServiceException("分区名称已维护");
        }

        //生成分区编码
        List<String> zoneCodes = dataCodeService.generateDataCodeNoList(DataCodeEnum.ZONE_CODE.getType(), pharmZoneList.size());
        for (int i = 0; i < pharmZoneList.size(); i++) {
            pharmZoneList.get(i).setZoneCode(zoneCodes.get(i));
            pharmZoneList.get(i).setId(IdUtils.fastUUID());
            preCreate(pharmZoneList.get(i));
        }

        //数据入库
        return super.saveBatch(pharmZoneList);
    }

    /**
     * 分区导出
     *
     * @param queryPage   分页
     * @param searchParam 模糊搜索(拼音码,五笔码,名称,编码)
     * @param isAll       是否查询全部 0-否，1-是
     * @param response
     */
    @Override
    public void zoneExport(Page<PharmZone> queryPage, String searchParam, String isAll, HttpServletResponse response) throws IOException {

        IPage<PharmZone> pharmZoneIPage = this.queryList(queryPage, searchParam, isAll, "0");
        if (pharmZoneIPage == null || pharmZoneIPage.getRecords().size() == 0) {
            throw new ServiceException("未获取到需要导出的数据");
        }

        //导出数据到excel
        EasyExcelUtils.extracted(response, pharmZoneIPage.getRecords(), PharmZone.class, "分区管理", "仓库分区");
    }
}
